import allure
import json
from pprint import pformat
import time
import datetime

from pyassured.core.emoji_utils import EmojiUtils
from pyassured.core.logger import Log

log = Log()


class LogHelper:
    """
    日志辅助类，用于封装重复的日志打印代码
    提供统一的日志记录和Allure报告附件添加方法
    """

    @staticmethod
    def log_assertion(assert_type, expected_value, actual_value, passed=True):
        """
        记录断言日志，并添加Allure报告附件
        
        Args:
            assert_type: 断言类型
            expected_value: 期望值
            actual_value: 实际值
            passed: 断言是否通过
        """
        # 为Allure报告添加附件
        allure.attach(name=f"{EmojiUtils.EXPECTED} 期望结果", body=str(expected_value))
        allure.attach(name=f"{EmojiUtils.ACTUAL} 实际结果", body=str(actual_value))

        # 格式化断言消息
        if assert_type:
            log_message = EmojiUtils.format_assert_message(
                assert_type,
                str(expected_value),
                str(actual_value).replace('\r', '').replace('\n', ''),
                passed
            )
        else:
            actual_value_str = str(actual_value).replace('\r', '').replace('\n', '')
            log_message = f"断言: {EmojiUtils.EXPECTED} 期望结果: {expected_value}, {EmojiUtils.ACTUAL} 实际结果: {actual_value_str}"

        # 记录日志
        if passed:
            log.success(log_message)
        else:
            log.error(log_message)

    @staticmethod
    def log_assertion_with_path(assert_type, expected_value, actual_value, passed=True, path_or_regex=None):
        """
        记录带有路径或正则表达式的断言日志，并添加Allure报告附件
        
        Args:
            assert_type: 断言类型
            expected_value: 期望值
            actual_value: 实际值
            passed: 断言是否通过
            path_or_regex: JSONPath路径或正则表达式
        """
        # 为Allure报告添加附件
        allure.attach(name=f"{EmojiUtils.EXPECTED} 期望结果", body=str(expected_value))
        allure.attach(name=f"{EmojiUtils.ACTUAL} 实际结果", body=str(actual_value))
        if path_or_regex:
            path_name = "JSONPath路径" if assert_type == "json_path" else "正则表达式"
            allure.attach(name=f"🔍 {path_name}", body=str(path_or_regex))

        # 格式化断言消息
        if assert_type:
            log_message = EmojiUtils.format_assert_message_with_path(
                assert_type,
                str(expected_value),
                str(actual_value).replace('\r', '').replace('\n', ''),
                passed,
                path_or_regex
            )
        else:
            actual_value_str = str(actual_value).replace('\r', '').replace('\n', '')
            log_message = f"断言: {EmojiUtils.EXPECTED} 期望结果: {expected_value}, {EmojiUtils.ACTUAL} 实际结果: {actual_value_str}"

        # 记录日志
        if passed:
            log.success(log_message)
        else:
            log.error(log_message)

    @staticmethod
    def log_extraction(extract_type, var_name, extract_value, scope="局部变量", key=None):
        """
        记录数据提取日志，并添加Allure报告附件
        
        Args:
            extract_type: 提取类型
            var_name: 变量名
            extract_value: 提取的值
            scope: 作用域
            key: 提取的键名
        """
        log_message = EmojiUtils.format_extract_message(extract_type, var_name, extract_value, scope, key)
        log.info(log_message)

        # 为Allure报告添加提取步骤
        step_title = f"{EmojiUtils.EXTRACT} 提取{extract_type}" + (f" : {key}" if key else "")
        with allure.step(step_title):
            if key:
                allure.attach(name=f"{extract_type}名称", body=key)
            allure.attach(name=f"变量名", body=var_name)
            allure.attach(name=f"提取值", body=str(extract_value))
            allure.attach(name=f"作用域", body=scope)

    @staticmethod
    def log_request(url, method, params=None, headers=None, data=None, json_data=None):
        """
        记录HTTP请求日志
        
        Args:
            url: 请求URL
            method: 请求方法
            params: 查询参数
            headers: 请求头
            data: 表单数据
            json_data: JSON数据
            
        Returns:
            float: 请求开始时间，用于计算响应时间
        """
        method_emoji = EmojiUtils.get_http_method_emoji(method)
        log.info("=" * 80)
        log.info(f"{EmojiUtils.REQUEST} 发送HTTP请求 {method_emoji} {method} | {EmojiUtils.TIME} {url}")
        log.info("-" * 80)

        if params:
            log.info(f"{EmojiUtils.DATA_LOCAL} 查询参数:\n{pformat(params, indent=4)}")

        if headers:
            log.info(f"{EmojiUtils.HEADER} 请求头:\n{pformat(headers, indent=4)}")

        if data:
            log.info(f"{EmojiUtils.BODY} 表单数据:\n{pformat(data, indent=4)}")

        if json_data:
            log.info(f"{EmojiUtils.JSON_DATA} JSON数据:\n{json.dumps(json_data, indent=4, ensure_ascii=False)}")

        log.info("=" * 80)

        return time.time()

    @staticmethod
    def log_response(response, start_time=None):
        """
        记录HTTP响应日志
        
        Args:
            response: HTTP响应对象
            start_time: 请求开始时间
            
        Returns:
            response: 原始响应对象
        """
        # 计算响应时间
        current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        response_time_ms = (time.time() - start_time) * 1000 if start_time else 0
        response_time = f"{response_time_ms:.2f}ms" if start_time else "未知"
        time_emoji = EmojiUtils.get_response_time_emoji(response_time_ms)

        # 获取状态码表情
        status_emoji = EmojiUtils.get_status_emoji(response.status_code)

        # 打印响应信息
        log.info("=" * 80)

        # 根据状态码使用不同的表情和描述
        status_desc = "成功" if 200 <= response.status_code < 300 else \
            "重定向" if 300 <= response.status_code < 400 else \
                "客户端错误" if 400 <= response.status_code < 500 else "服务器错误"

        log.info(f"{EmojiUtils.RESPONSE} 收到HTTP响应 {status_emoji} {status_desc} | {EmojiUtils.TIME} {current_time}")
        log.info("-" * 80)

        # 打印状态码和响应时间
        log.info(f"{EmojiUtils.ASSERT_STATUS} 状态码: {response.status_code}")
        log.info(f"{time_emoji} 响应时间: {response_time}")

        # 打印响应头 (可选择性打印重要头信息)
        content_type = response.headers.get('Content-Type', '未知')
        log.info(f"{EmojiUtils.HEADER} Content-Type: {content_type}")

        # 打印响应体
        try:
            response_body = response.json()
            log.info(
                f"{EmojiUtils.JSON_DATA} 响应体 (JSON):\n{json.dumps(response_body, indent=4, ensure_ascii=False)}")
        except:
            response_body = response.text
            # 如果响应体太长，可以截断显示
            if len(response_body) > 1000:
                log.info(f"{EmojiUtils.BODY} 响应体 (文本, 截取前1000字符):\n{response_body[:1000]}...")
            else:
                log.info(f"{EmojiUtils.BODY} 响应体 (文本):\n{response_body}")

        log.info("=" * 80)

        return response

    @staticmethod
    def add_allure_request_attachments(url, method, params=None, headers=None, data=None, json_data=None):
        """
        为Allure报告添加请求附件
        
        Args:
            url: 请求URL
            method: 请求方法
            params: 查询参数
            headers: 请求头
            data: 表单数据
            json_data: JSON数据
        """
        method_emoji = EmojiUtils.get_http_method_emoji(method)
        allure.attach(name=f"{EmojiUtils.URL} 请求URL", body=url)
        allure.attach(name=f"{method_emoji} 请求方法", body=str(method))

        if headers:
            allure.attach(name=f"{EmojiUtils.HEADER} 请求头",
                          body=json.dumps(headers, indent=2, ensure_ascii=False),
                          attachment_type=allure.attachment_type.JSON)

        if params:
            allure.attach(name=f"{EmojiUtils.VARIABLE} 查询参数",
                          body=json.dumps(params, indent=2, ensure_ascii=False),
                          attachment_type=allure.attachment_type.JSON)

        if data:
            if isinstance(data, dict):
                allure.attach(name=f"{EmojiUtils.BODY} 请求表单数据",
                              body=json.dumps(data, indent=2, ensure_ascii=False),
                              attachment_type=allure.attachment_type.JSON)
            else:
                allure.attach(name=f"{EmojiUtils.BODY} 请求表单数据", body=str(data))

        if json_data:
            allure.attach(name=f"{EmojiUtils.JSON_DATA} 请求JSON数据",
                          body=json.dumps(json_data, indent=2, ensure_ascii=False),
                          attachment_type=allure.attachment_type.JSON)

    @staticmethod
    def add_allure_response_attachments(response):
        """
        为Allure报告添加响应附件
        
        Args:
            response: HTTP响应对象
        """
        if response:
            # 获取状态码表情
            status_code = response.status_code
            status_emoji = EmojiUtils.get_status_emoji(status_code)

            # 计算响应时间
            response_time = response.elapsed.total_seconds() * 1000
            time_emoji = EmojiUtils.get_response_time_emoji(response_time)

            # 记录响应状态码和响应时间
            allure.attach(name=f"{status_emoji} 响应状态码",
                          body=f"{status_code} ({response_time:.2f}ms)")

            allure.attach(name=f"{EmojiUtils.HEADER} 响应头",
                          body=json.dumps(dict(response.headers), indent=2, ensure_ascii=False),
                          attachment_type=allure.attachment_type.JSON)

            # 尝试以JSON格式记录响应
            try:
                response_body = response.json()
                allure.attach(name=f"{EmojiUtils.JSON_DATA} 响应数据",
                              body=json.dumps(response_body, indent=2, ensure_ascii=False),
                              attachment_type=allure.attachment_type.JSON)
            except ValueError:
                # 如果不是JSON，则以文本形式记录
                allure.attach(name=f"{EmojiUtils.BODY} 响应数据", body=response.text)
